" Check python support
if !has('python')
    echo "Error: PyFlake.vim required vim compiled with +python."
    finish
endif

if !exists('g:PyFlakeRangeCommand')
    let g:PyFlakeRangeCommand = 'Q'
endif

if !exists('b:PyFlake_initialized')
    let b:PyFlake_initialized = 1

    au BufWritePost <buffer> call flake8#on_write()
    au CursorHold <buffer> call flake8#get_message()
    au CursorMoved <buffer> call flake8#get_message()
    
    " Commands
    command! -buffer PyFlakeToggle :let b:PyFlake_disabled = exists('b:PyFlake_disabled') ? b:PyFlake_disabled ? 0 : 1 : 1
    command! -buffer PyFlake :call flake8#run()
    command! -buffer -range=% PyFlakeAuto :call flake8#auto(<line1>,<line2>)

    " Keymaps
    if g:PyFlakeRangeCommand != ''
        exec 'vnoremap <buffer> <silent> ' . g:PyFlakeRangeCommand . ' :PyFlakeAuto<CR>'
    endif

    let b:showing_message = 0
    
    " Signs definition
    sign define W text=WW texthl=Todo
    sign define C text=CC texthl=Comment
    sign define R text=RR texthl=Visual
    sign define E text=EE texthl=Error
endif

 "Check for flake8 plugin is loaded
if exists("g:PyFlakeDirectory")
    finish
endif

if !exists('g:PyFlakeOnWrite')
    let g:PyFlakeOnWrite = 1
endif

" Init variables
let g:PyFlakeDirectory = expand('<sfile>:p:h')

if !exists('g:PyFlakeCheckers')
    let g:PyFlakeCheckers = 'pep8,mccabe,pyflakes'
endif
if !exists('g:PyFlakeDefaultComplexity')
    let g:PyFlakeDefaultComplexity=10
endif
if !exists('g:PyFlakeDisabledMessages')
    let g:PyFlakeDisabledMessages = 'E501'
endif
if !exists('g:PyFlakeCWindow')
    let g:PyFlakeCWindow = 6
endif
if !exists('g:PyFlakeSigns')
    let g:PyFlakeSigns = 1
endif
if !exists('g:PyFlakeMaxLineLength')
    let g:PyFlakeMaxLineLength = 100
endif

python << EOF

import sys
import json
import vim

sys.path.insert(0, vim.eval("g:PyFlakeDirectory"))
from flake8 import run_checkers, fix_lines, Pep8Options, MccabeOptions

def flake8_check():
    checkers=vim.eval('g:PyFlakeCheckers').split(',')
    ignore=vim.eval('g:PyFlakeDisabledMessages').split(',')
    MccabeOptions.complexity=int(vim.eval('g:PyFlakeDefaultComplexity'))
    Pep8Options.max_line_length=int(vim.eval('g:PyFlakeMaxLineLength'))
    filename=vim.current.buffer.name
    parse_result(run_checkers(filename, checkers, ignore))

def parse_result(result):
    vim.command('let g:qf_list = {}'.format(json.dumps(result, ensure_ascii=False)))

EOF

function! flake8#on_write()
    if !g:PyFlakeOnWrite || exists("b:PyFlake_disabled") && b:PyFlake_disabled
        return
    endif
    call flake8#check()
endfunction

function! flake8#run()
    if &modifiable && &modified
        write
    endif
    call flake8#check()
endfun

function! flake8#check()
    py flake8_check()
    let s:matchDict = {}
    for err in g:qf_list
        let s:matchDict[err.lnum] = err.text
    endfor
    call setqflist(g:qf_list, 'r')

    " Place signs
    if g:PyFlakeSigns
        call flake8#place_signs()
    endif

    " Open cwindow
    if g:PyFlakeCWindow
        cclose
        if len(g:qf_list)
            let l:winsize = len(g:qf_list) > g:PyFlakeCWindow ? g:PyFlakeCWindow : len(g:qf_list)
            exec l:winsize . 'cwindow'
        endif
    endif
endfunction

function! flake8#auto(l1, l2) "{{{
    cclose
    sign unplace *
    let s:matchDict = {}
    call setqflist([])

python << EOF
start, end = int(vim.eval('a:l1'))-1, int(vim.eval('a:l2'))
enc = vim.eval('&enc')
lines = fix_lines(vim.current.buffer[start:end]).splitlines()
res = [ln.encode(enc, 'replace') for ln in lines]
vim.current.buffer[start:end] = res
EOF
endfunction "}}}

function! flake8#place_signs()
    "first remove all sings
    sign unplace *

    "now we place one sign for every quickfix line
    let l:id = 1
    for item in getqflist()
        execute(':sign place '.l:id.' name='.l:item.type.' line='.l:item.lnum.' buffer='.l:item.bufnr)
        let l:id = l:id + 1
    endfor
endfunction

" keep track of whether or not we are showing a message
" WideMsg() prints [long] message up to (&columns-1) length
" guaranteed without "Press Enter" prompt.
function! flake8#wide_msg(msg)
    let x=&ruler | let y=&showcmd
    set noruler noshowcmd
    redraw
    echo strpart(a:msg, 0, &columns-1)
    let &ruler=x | let &showcmd=y
endfun


function! flake8#get_message()
    let s:cursorPos = getpos(".")

    " Bail if RunPyflakes hasn't been called yet.
    if !exists('s:matchDict')
        return
    endif

    " if there's a message for the line the cursor is currently on, echo
    " it to the console
    if has_key(s:matchDict, s:cursorPos[1])
        let s:pyflakesMatch = get(s:matchDict, s:cursorPos[1])
        call flake8#wide_msg(s:pyflakesMatch)
        let b:showing_message = 1
        return
    endif

    " otherwise, if we're showing a message, clear it
    if b:showing_message == 1
        echo
        let b:showing_message = 0
    endif
endfunction
